﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace OsuTool
{
    class KeyPositionConverter
    {
        /// <summary>
        /// 谱面键数
        /// </summary>
        public int KeyCount { get; set; }

        /// <summary>
        /// 目标谱面键数
        /// </summary>
        public int AimKeyCount { get; set; }

        /// <summary>
        /// 转谱模式
        /// </summary>
        public List<int> ConvertMode { get; set; }

        private readonly string _convertString;

        private ConvertKeyPositionState _convertKeyPositionState = ConvertKeyPositionState.None;

        public KeyPositionConverter(int keyCount, int aimKeyCount, string convertMode)
        {
            KeyCount = keyCount;
            AimKeyCount = aimKeyCount;
            ConvertMode = new List<int>(AimKeyCount);
            foreach (var t in convertMode)
            {
                ConvertMode.Add(t == 'a' ? 10 : Convert.ToInt32(t.ToString()));
            }

            _convertString = convertMode;
        }

        public KeyPositionConverter()
        {

        }

        /// <summary>
        /// 计算得目标键在谱面中的横坐标
        /// </summary>
        /// <param name="keyPosition"></param>
        /// <returns></returns>
        public List<int> GetAimKeyPositionList(int keyPosition)
        {
            var keyNumber = OsuFileInfo.KeyPositionToKeyNumber(KeyCount, keyPosition);
            //根据原始横坐标获取其对应的键轨道名，在通过键轨道名在ConvertMode中的对应目标键轨道名获取目标键轨道横坐标列表
            var result = new List<int>();
            for (var i = 0; i < ConvertMode.Count; i++)
            {
                if (ConvertMode[i] != keyNumber) continue;
                var position = OsuFileInfo.KeyNumberToKeyPosition(AimKeyCount, i);
                result.Add(position);
            }

            return result;
        }

        public void ConvertKepPosition(string file)
        {
            var aimDifficulty = $@" [{KeyCount}k to {AimKeyCount}k Mode-{_convertString}]";
            var aimFile = file.Replace(".osu", "") + aimDifficulty + ".osu";
            StreamWriter writer = null;
            _convertKeyPositionState = ConvertKeyPositionState.ChangeVersion;
            using (var reader = new StreamReader(file))
            {
                var line = reader.ReadLine();
                var basicStr = new StringBuilder();
                while (line != null)
                {
                    if (_convertKeyPositionState == ConvertKeyPositionState.ChangeVersion)
                    {
                        if (line.Contains(OsuFileInfo.StrVersion))
                        {
                            line += aimDifficulty;
                            _convertKeyPositionState = ConvertKeyPositionState.JudgeKeysCount;
                            basicStr.Append(line);
                            basicStr.Append("\n");
                            line = reader.ReadLine();
                            continue;
                        }

                        basicStr.Append(line);
                        basicStr.Append("\n");
                    }

                    if (_convertKeyPositionState == ConvertKeyPositionState.JudgeKeysCount)
                    {
                        if (line.Contains(OsuFileInfo.StrCircleSize))
                        {
                            if (Convert.ToInt32(line.Substring(line.Length - 1)) != KeyCount)
                            {
                                return;
                            }

                            basicStr.Append(line.Replace(KeyCount.ToString(), AimKeyCount.ToString()));
                            var fs = !File.Exists(aimFile)
                                ? new FileStream(aimFile, FileMode.Create, FileAccess.Write)
                                : new FileStream(aimFile, FileMode.Open, FileAccess.Write);

                            writer = new StreamWriter(fs);
                            writer.WriteLine(basicStr.ToString());
                            _convertKeyPositionState = ConvertKeyPositionState.ReadyWriteHitObject;
                            line = reader.ReadLine();
                            continue;
                        }

                        basicStr.Append(line);
                        basicStr.Append("\n");
                    }

                    if (_convertKeyPositionState == ConvertKeyPositionState.ReadyWriteHitObject)
                    {
                        writer?.WriteLine(line);
                        if (line.Contains(OsuFileInfo.StrHitObjects))
                        {
                            _convertKeyPositionState = ConvertKeyPositionState.WriteHitObject;
                            line = reader.ReadLine();
                            continue;
                        }
                    }

                    if (_convertKeyPositionState == ConvertKeyPositionState.WriteHitObject)
                    {
                        var index = line.IndexOf(',');
                        var leftStr = line.Substring(index);
                        var positionStr = line.Replace(leftStr, "");
                        var keyPosition = Convert.ToInt32(positionStr);
                        var aimKeyPositionList = GetAimKeyPositionList(keyPosition);
                        foreach (var position in aimKeyPositionList)
                        {
                            var crtLine = position + leftStr;
                            writer.WriteLine(crtLine);
                        }
                    }

                    line = reader.ReadLine();
                }

                if (writer == null) return;
                writer.Close();
                writer.Dispose();
            }
        }
    }

    internal enum ConvertKeyPositionState
    {
        JudgeKeysCount,
        ChangeVersion,
        WriteHitObject,
        ReadyWriteHitObject,
        None
    }
}